home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / hobby / ast44src.zip / XSCREEN.C < prev   
C/C++ Source or Header  |  1995-02-11  |  51KB  |  1,737 lines

  1. /*
  2. ** Astrolog (Version 4.40) File: xscreen.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. #ifdef GRAPH
  41. /*
  42. ******************************************************************************
  43. ** Astrolog Icon.
  44. ******************************************************************************
  45. */
  46.  
  47. #ifdef X11
  48. /* This information used to define Astrolog's X icon (Rainbow over Third */
  49. /* Eye) is identical to the output format used by the bitmap program.    */
  50. /* You could extract this section and run xsetroot -bitmap on it.        */
  51.  
  52. #define icon_width 63
  53. #define icon_height 32
  54. static char icon_bits[] = {
  55.  0x00,0x00,0x00,0xa8,0x0a,0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x55,0x01,0x00,
  56.  0x00,0x00,0x00,0xa8,0xaa,0xaa,0x0a,0x00,0x00,0x00,0x00,0x54,0xf5,0x57,0x15,
  57.  0x00,0x00,0x00,0x80,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x40,0xd5,0xff,0xff,
  58.  0x55,0x01,0x00,0x00,0xa0,0xaa,0xaa,0xaa,0xaa,0x02,0x00,0x00,0x50,0xfd,0xff,
  59.  0xff,0x5f,0x05,0x00,0x00,0xa8,0xaa,0x2a,0xaa,0xaa,0x0a,0x00,0x00,0xd4,0xff,
  60.  0xaf,0xfa,0xff,0x15,0x00,0x00,0xaa,0x2a,0x00,0x00,0xaa,0x2a,0x00,0x00,0xf5,
  61.  0xbf,0xaa,0xaa,0xfe,0x57,0x00,0x80,0xaa,0x02,0x00,0x00,0xa0,0xaa,0x00,0x40,
  62.  0xfd,0xab,0xfa,0xaf,0xea,0x5f,0x01,0xa0,0xaa,0x80,0xff,0xff,0x80,0xaa,0x02,
  63.  0x50,0xff,0xea,0xff,0xff,0xab,0x7f,0x05,0xa0,0x2a,0xf0,0xff,0xff,0x07,0xaa,
  64.  0x02,0xd0,0xbf,0xfa,0x0f,0xf8,0xaf,0x7e,0x05,0xa8,0x0a,0xfc,0x01,0xc0,0x1f,
  65.  0xa8,0x0a,0xd4,0xaf,0x7e,0x00,0x00,0xbf,0xfa,0x15,0xa8,0x0a,0x3f,0x00,0x00,
  66.  0x7e,0xa8,0x0a,0xf4,0xaf,0x1f,0xe0,0x03,0xfc,0xfa,0x15,0xaa,0x82,0x0f,0xdc,
  67.  0x1d,0xf8,0xa0,0x2a,0xf4,0xab,0x07,0x23,0x62,0xf0,0xea,0x17,0xaa,0xc2,0x87,
  68.  0x91,0xc4,0xf0,0xa1,0x2a,0xf4,0xeb,0xc3,0xd0,0x85,0xe1,0xeb,0x17,0xaa,0xe0,
  69.  0x83,0x91,0xc4,0xe0,0x83,0x2a,0xf5,0xeb,0x03,0x23,0x62,0xe0,0xeb,0x57,0xaa,
  70.  0xe0,0x01,0xdc,0x1d,0xc0,0x83,0x2a,0xf5,0xeb,0x01,0xe0,0x03,0xc0,0xeb,0x57,
  71.  0xaa,0xe0,0x01,0x00,0x00,0xc0,0x83,0x2a,0xfd,0xeb,0x01,0x00,0x00,0xc0,0xeb,
  72.  0x5f};
  73. #endif
  74.  
  75.  
  76. /*
  77. ******************************************************************************
  78. ** Interactive Screen Graphics Routines.
  79. ******************************************************************************
  80. */
  81.  
  82. /* Set up all the colors used by the program, i.e. the foreground and   */
  83. /* background colors, and all the colors in the object arrays, based on */
  84. /* whether or not we are in monochrome and/or reverse video mode.       */
  85.  
  86. void InitColorsX()
  87. {
  88.   int i;
  89. #ifdef X11
  90.   Colormap cmap;
  91.   XColor xcol;
  92.  
  93.   if (!gi.fFile) {
  94.     cmap = XDefaultColormap(gi.disp, gi.screen);
  95.  
  96.     /* Allocate a color from the present X11 colormap. Given a string like */
  97.     /* "violet", allocate this color and return a value specifying it.     */
  98.  
  99.     for (i = 0; i < 16; i++) {
  100.       XParseColor(gi.disp, cmap, szColorX[i], &xcol);
  101.       XAllocColor(gi.disp, cmap, &xcol);
  102.       rgbind[i] = xcol.pixel;
  103.     }
  104.   }
  105. #endif
  106.   gi.kiOn   = kMainA[!gs.fInverse];
  107.   gi.kiOff  = kMainA[gs.fInverse];
  108.   gi.kiLite = gs.fColor ? kMainA[2+gs.fInverse] : gi.kiOn;
  109.   gi.kiGray = gs.fColor ? kMainA[3-gs.fInverse] : gi.kiOn;
  110.   for (i = 0; i <= 8; i++)
  111.     kMainB[i]    = gs.fColor ? kMainA[i]    : gi.kiOn;
  112.   for (i = 0; i <= 7; i++)
  113.     kRainbowB[i] = gs.fColor ? kRainbowA[i] : gi.kiOn;
  114.   for (i = 0; i < 4; i++)
  115.     kElemB[i]    = gs.fColor ? kElemA[i]    : gi.kiOn;
  116.   for (i = 0; i <= cAspect; i++)
  117.     kAspB[i]     = gs.fColor ? kAspA[i]     : gi.kiOn;
  118.   for (i = 0; i <= cObj; i++)
  119.     kObjB[i]     = gs.fColor ? kObjA[i]     : gi.kiOn;
  120. #ifdef X11
  121.   if (!gi.fFile) {
  122.     XSetBackground(gi.disp, gi.gc,   rgbind[gi.kiOff]);
  123.     XSetForeground(gi.disp, gi.pmgc, rgbind[gi.kiOff]);
  124.   }
  125. #endif
  126. }
  127.  
  128.  
  129. #ifdef ISG
  130. /* This routine opens up and initializes a window and prepares it to be */
  131. /* drawn upon, and gets various information about the display, too.     */
  132.  
  133. void BeginX()
  134. {
  135. #ifdef X11
  136.   gi.disp = XOpenDisplay(gs.szDisplay);
  137.   if (gi.disp == NULL) {
  138.     PrintError("Can't open display.");
  139.     Terminate(tcFatal);
  140.   }
  141.   gi.screen = DefaultScreen(gi.disp);
  142.   bg = BlackPixel(gi.disp, gi.screen);
  143.   fg = WhitePixel(gi.disp, gi.screen);
  144.   hint.x = gi.xOffset; hint.y = gi.yOffset;
  145.   hint.width = gs.xWin; hint.height = gs.yWin;
  146.   hint.min_width = BITMAPX1; hint.min_height = BITMAPY1;
  147.   hint.max_width = BITMAPX;  hint.max_height = BITMAPY;
  148.   hint.flags = PPosition | PSize | PMaxSize | PMinSize;
  149. #if FALSE
  150.   wmhint = XGetWMHints(gi.disp, gi.wind);
  151.   wmhint->input = True;
  152.   XSetWMHints(gi.disp, gi.wind, wmhint);
  153. #endif
  154.   gi.depth = DefaultDepth(gi.disp, gi.screen);
  155.   if (gi.depth < 5) {
  156.     gi.fMono = fTrue;      /* Is this a monochrome monitor? */
  157.     gs.fColor = fFalse;
  158.   }
  159.   gi.root = RootWindow(gi.disp, gi.screen);
  160.   if (gs.fRoot)
  161.     gi.wind = gi.root;     /* If -XB in effect, we'll use the root window. */
  162.   else
  163.     gi.wind = XCreateSimpleWindow(gi.disp, DefaultRootWindow(gi.disp),
  164.       hint.x, hint.y, hint.width, hint.height, 5, fg, bg);
  165.   gi.pmap = XCreatePixmap(gi.disp, gi.wind, gs.xWin, gs.yWin, gi.depth);
  166.   gi.icon = XCreateBitmapFromData(gi.disp, DefaultRootWindow(gi.disp),
  167.     icon_bits, icon_width, icon_height);
  168.   if (!gs.fRoot)
  169.     XSetStandardProperties(gi.disp, gi.wind, szAppName, szAppName, gi.icon,
  170.       (char **)xkey, 0, &hint);
  171.  
  172.   /* We have two graphics workareas. One is what the user currently sees in */
  173.   /* the window, and the other is what we are currently drawing on. When    */
  174.   /* done, we can quickly copy this to the viewport for a smooth look.      */
  175.  
  176.   gi.gc = XCreateGC(gi.disp, gi.wind, 0, 0);
  177.   XSetGraphicsExposures(gi.disp, gi.gc, 0);
  178.   gi.pmgc = XCreateGC(gi.disp, gi.wind, 0, 0);
  179.   InitColorsX();                           /* Go set up colors. */
  180.   if (!gs.fRoot)
  181.     XSelectInput(gi.disp, gi.wind, KeyPressMask | StructureNotifyMask |
  182.       ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
  183.   XMapRaised(gi.disp, gi.wind);
  184.   XSync(gi.disp, 0);
  185.   XFillRectangle(gi.disp, gi.pmap, gi.pmgc, 0, 0, gs.xWin, gs.yWin);
  186. #endif /* X11 */
  187.  
  188. #ifdef MSG
  189.   if (!FValidResmode(gi.nRes))    /* Initialize graphics mode to hi-res. */
  190.     gi.nRes = gs.nResHi;
  191.   _setvideomode(gi.nRes);
  192.   if (_grstatus()) {
  193.     PrintError("Can't enter graphics mode.");
  194.     Terminate(tcFatal);
  195.   }
  196.   _getvideoconfig((struct videoconfig far *) &gi.cfg);
  197.   if (gi.cfg.numcolors < 16) {
  198.     gi.fMono  = fTrue;
  199.     gs.fColor = fFalse;
  200.   }
  201.   _remapallpalette((long FAR *) rgb);
  202.   _setactivepage(0);
  203.   _setvisualpage(0);
  204.   InitColorsX();
  205. #ifdef MOUSE
  206.   MouseInit(xPcScreen, yPcScreen);
  207. #endif
  208.   /* Make sure we reset textrows upon restart. */
  209.   gs.nTextRows = abs(gs.nTextRows);
  210. #endif /* MSG */
  211.  
  212. #ifdef BGI
  213.   int i;
  214.   static struct palettetype pal;
  215.  
  216.   if (!FValidResmode(gi.nRes))    /* Initialize graphics mode to hi-res. */
  217.     gi.nRes = gs.nResHi;
  218.   if (!gi.fLoaded) {
  219.     registerfarbgidriver(ATT_driver_far);      /* attf.obj     */
  220.     registerfarbgidriver(CGA_driver_far);      /* cgaf.obj     */
  221.     registerfarbgidriver(EGAVGA_driver_far);   /* egavgaf.obj  */
  222.     registerfarbgidriver(Herc_driver_far);     /* hercf.obj    */
  223.     registerfarbgidriver(IBM8514_driver_far);  /* ibm8514f.obj */
  224.     registerfarbgidriver(PC3270_driver_far);   /* pc3270f.obj  */
  225.     gi.nDriver = DETECT;
  226.     initgraph(&gi.nDriver, &gi.nGraph, "");
  227.     gi.fLoaded = fTrue;
  228.   }
  229.   if (gi.nRes <= 0) {
  230.     switch (gi.nDriver) {
  231.     case CGA:      gi.nGraph = CGAHI;      break;
  232.     case MCGA:     gi.nGraph = MCGAHI;     break;
  233.     case EGA:      gi.nGraph = EGAHI;      break;
  234.     case EGA64:    gi.nGraph = EGA64HI;    break;
  235.     case EGAMONO:  gi.nGraph = EGAMONOHI;  break;
  236.     case HERCMONO: gi.nGraph = HERCMONOHI; break;
  237.     case ATT400:   gi.nGraph = ATT400HI;   break;
  238.     case VGA:      gi.nGraph = VGAHI;      break;
  239.     case PC3270:   gi.nGraph = PC3270HI;   break;
  240.     case IBM8514:  gi.nGraph = IBM8514HI;  break;
  241.     default:       gi.nGraph = 0;
  242.     }
  243.   } else {
  244.     switch (gi.nDriver) {
  245.     case CGA:      gi.nGraph = CGAHI;      break;
  246.     case MCGA:     gi.nGraph = MCGAHI;     break;
  247.     case EGA:      gi.nGraph = EGAHI;      break;
  248.     case EGA64:    gi.nGraph = EGA64HI;    break;
  249.     case EGAMONO:  gi.nGraph = EGAMONOHI;  break;
  250.     case HERCMONO: gi.nGraph = HERCMONOHI; break;
  251.     case ATT400:   gi.nGraph = ATT400HI;   break;
  252.     case VGA:      gi.nGraph = VGAMED;     break;
  253.     case PC3270:   gi.nGraph = PC3270HI;   break;
  254.     case IBM8514:  gi.nGraph = IBM8514LO;  break;
  255.     default:       gi.nGraph = 0;
  256.     }
  257.   }
  258.   setgraphmode(gi.nGraph);
  259.   if (graphresult()) {
  260.     PrintError("Can't enter graphics mode.");
  261.     Terminate(tcFatal);
  262.   }
  263.   gi.nPages = 1 + (gi.nDriver == HERCMONO ||
  264.     (gi.nDriver == VGA && gi.nGraph != VGAHI) || gi.nDriver == EGA);
  265.   if (getmaxcolor()+1 < 16) {
  266.     gi.fMono  = fTrue;
  267.     gs.fColor = fFalse;
  268.   }
  269.   getpalette(&pal);
  270.   for (i = 0; i < pal.size; i++)
  271.     pal.colors[i] = (char)rgb[i];
  272.   setallpalette(&pal);
  273.   setactivepage(0);
  274.   setvisualpage(0);
  275.   gi.nPageCur = 0;
  276.   InitColorsX();
  277. #ifdef MOUSE
  278.   MouseInit(xPcScreen, yPcScreen);
  279. #endif
  280.   /* Make sure we reset textrows upon restart. */
  281.   gs.nTextRows = abs(gs.nTextRows);
  282. #endif /* BGI */
  283. }
  284.  
  285.  
  286. /* Add a certain amount of time to the current hour/day/month/year quantity */
  287. /* defining the present chart. This is used by the chart animation feature. */
  288. /* We can add or subtract anywhere from 1 to 9 seconds, minutes, hours,     */
  289. /* days, months, years, decades, centuries, or millenia in any one call.    */
  290. /* This is mainly just addition to the appropriate quantity, but we have    */
  291. /* to check for overflows, e.g. Dec 30 + 3 days = Jan 2 of Current year + 1 */
  292.  
  293. void AddTime(mode, toadd)
  294. int mode, toadd;
  295. {
  296.   int d;
  297.   real h, m;
  298.  
  299.   if (!FBetween(mode, 1, 9))
  300.     mode = 4;
  301.  
  302.   h = RFloor(TT);
  303.   m = RFract(TT)*100.0;
  304.   if (mode == 1)
  305.     m += 1.0/60.0*(real)toadd;    /* Add seconds. */
  306.   else if (mode == 2)
  307.     m += (real)toadd;             /* add minutes. */
  308.  
  309.   /* Add hours, either naturally or if minute value overflowed. */
  310.  
  311.   if (m < 0.0 || m >= 60.0 || mode == 3) {
  312.     if (m >= 60.0) {
  313.       m -= 60.0; toadd = NSgn(toadd);
  314.     } else if (m < 0.0) {
  315.       m += 60.0; toadd = NSgn(toadd);
  316.     }
  317.     h += (real)toadd;
  318.   }
  319.  
  320.   /* Add days, either naturally or if hour value overflowed. */
  321.  
  322.   if (h >= 24.0 || h < 0.0 || mode == 4) {
  323.     if (h >= 24.0) {
  324.       h -= 24.0; toadd = NSgn(toadd);
  325.     } else if (h < 0.0) {
  326.       h += 24.0; toadd = NSgn(toadd);
  327.     }
  328.     DD = AddDay(MM, DD, YY, toadd);
  329.   }
  330.  
  331.   /* Add months, either naturally or if day value overflowed. */
  332.  
  333.   if (DD > (d = DayInMonth(MM, YY)) || DD < 1 || mode == 5) {
  334.     if (DD > d) {
  335.       DD -= d; toadd = NSgn(toadd);
  336.     } else if (DD < 1) {
  337.       DD += DayInMonth(Mod12(MM - 1), YY);
  338.       toadd = NSgn(toadd);
  339.     }
  340.     MM += toadd;
  341.   }
  342.  
  343.   /* Add years, either naturally or if month value overflowed. */
  344.  
  345.   if (MM > 12 || MM < 1 || mode == 6) {
  346.     if (MM > 12) {
  347.       MM -= 12; toadd = NSgn(toadd);
  348.     } else if (MM < 1) {
  349.       MM += 12; toadd = NSgn(toadd);
  350.     }
  351.     YY += toadd;
  352.   }
  353.   if (mode == 7)
  354.     YY += 10 * toadd;      /* Add decades.   */
  355.   else if (mode == 8)
  356.     YY += 100 * toadd;     /* Add centuries. */
  357.   else if (mode == 9)
  358.     YY += 1000 * toadd;    /* Add millenia.  */
  359.   TT = h+m/100.0;          /* Recalibrate hour time. */
  360. }
  361.  
  362.  
  363. /* Animate the current chart based on the given values indicating how much  */
  364. /* to update by. We update and recast the current chart info appropriately. */
  365.  
  366. void Animate(mode, toadd)
  367. int mode, toadd;
  368. {
  369.   if (gi.nMode == gWorldMap || gi.nMode == gGlobe || gi.nMode == gPolar) {
  370.     gs.nRot += toadd;
  371.     if (gs.nRot >= nDegMax)     /* For animating globe display, add */
  372.       gs.nRot -= nDegMax;       /* in appropriate degree value.     */
  373.     else if (gs.nRot < 0)
  374.       gs.nRot += nDegMax;
  375.   } else {
  376.     if (mode == 10) {
  377. #ifdef TIME
  378.       /* For the continuous chart update to present moment */
  379.       /* animation mode, go get whatever time it is now.   */
  380.       FInputData(szNowCore);
  381. #else
  382.       ciCore = ciMain;
  383.       AddTime(1, toadd);
  384. #endif
  385.     } else {  /* Otherwise add on appropriate time vector to chart info. */
  386.       ciCore = ciMain;
  387.       AddTime(mode, toadd);
  388.     }
  389.     ciMain = ciCore;
  390.     if (us.nRel)
  391.       CastRelation(fFalse);
  392.     else
  393.       CastChart(fTrue);
  394.   }
  395. }
  396.  
  397.  
  398. /* This routine exits graphics mode, prompts the user for a set of command */
  399. /* switches, processes them, and returns to the previous graphics with the */
  400. /* new settings in effect, allowing one to change most any setting without */
  401. /* having to lose their graphics state or fall way back to a -Q loop.      */
  402.  
  403. void CommandLineX()
  404. {
  405.   char szCommandLine[cchSzMax], *rgsz[MAXSWITCHES];
  406.   int argc, fT, fPause = fFalse;
  407.  
  408.   ciCore = ciMain;
  409. #ifdef MSG
  410.   _setvideomode(_DEFAULTMODE);
  411.   _settextrows(gs.nTextRows);
  412. #endif
  413. #ifdef BGI
  414.   restorecrtmode();
  415.   if (gs.nTextRows > 25)
  416.     textmode(C4350);
  417. #endif
  418.   fT = us.fLoop; us.fLoop = fTrue;
  419.   argc = NPromptSwitches(szCommandLine, rgsz);
  420.   is.cchRow = 0;
  421.   is.fSzInteract = fTrue;
  422.   if (!FProcessSwitches(argc, rgsz))
  423.     fPause = fTrue;
  424.   else {
  425.     is.fMult = fFalse;
  426.     FPrintTables();
  427.     if (is.fMult) {
  428.       ClearB((lpbyte)&us.fCredit,
  429.         (int)((lpbyte)&us.fLoop - (lpbyte)&us.fCredit));
  430.       fPause = fTrue;
  431.     }
  432.   }
  433.  
  434. #ifdef PCG
  435.   /* Pause for the user if there was either an error processing the    */
  436.   /* switches, or one of the informational text tables was brought up. */
  437.  
  438.   if (fPause) {
  439.     AnsiColor(kDefault);
  440.     is.cchRow = 0;
  441.     PrintSz("Press any key to return to graphics.\n");
  442.     while (!kbhit())
  443.       ;
  444.     getch();
  445.   }
  446. #endif
  447.   is.fSzInteract = fFalse;
  448.   us.fLoop = fT;
  449.   ciMain = ciCore;
  450.   BeginX();
  451. }
  452.  
  453.  
  454. /* Given two chart size values, adjust them such that the chart will look */
  455. /* "square". We round the higher value down and check certain conditions. */
  456.  
  457. void SquareX(x, y, force)
  458. int *x, *y, force;
  459. {
  460.   if (!force && !fSquare)    /* Unless we want to force a square, realize */
  461.     return;                  /* that some charts look better rectangular. */
  462.   if (*x > *y)
  463.     *x = *y;
  464.   else
  465.     *y = *x;
  466. #ifdef PCG
  467.   if (FEgaRes(gi.nRes))         /* Scale horizontal size if we're in a PC */
  468.     *x = VgaFromEga(*x);        /* graphics mode without "square" pixels. */
  469.   else if (FCgaRes(gi.nRes))
  470.     *x = VgaFromCga(*x);
  471. #endif
  472.   if (fSidebar)      /* Take into account chart's sidebar, if any. */
  473.     *x += xSideT;
  474. }
  475.  
  476.  
  477. /* This routine gets called after graphics are brought up and displayed     */
  478. /* on the screen. It loops, processing key presses, mouse clicks, etc, that */
  479. /* the window receives, until the user specifies they want to exit program. */
  480.  
  481. void InteractX()
  482. {
  483. #ifdef X11
  484.   char sz[cchSzDef];
  485.   XEvent xevent;
  486.   KeySym keysym;
  487.   int fResize = fFalse, fRedraw = fTrue;
  488. #else /* PCG */
  489. #ifdef MOUSE
  490.   int eventx, eventy, eventbtn;
  491. #endif
  492.   int fResize = fTrue, fRedraw = fFalse;
  493. #endif /* PCG */
  494.   int fBreak = fFalse, fPause = fFalse, fCast = fFalse, xcorner = 7,
  495.     mousex = -1, mousey = -1, buttonx = -1, buttony = -1, dir = 1,
  496.     length, key, i;
  497.   bool fT;
  498.   KI coldrw = gi.kiLite;
  499.  
  500.   neg(gs.nAnim);
  501.   while (!fBreak) {
  502.     gi.nScale = gs.nScale/100;
  503.  
  504.     /* Some chart windows, like the world maps and aspect grids, should */
  505.     /* always be a certian size, so correct if a resize was attempted.  */
  506.  
  507.     if (fMap) {
  508.       length = nDegMax*gi.nScale;
  509.       if (gs.xWin != length) {
  510.         gs.xWin = length;
  511.         fResize = fTrue;
  512.       }
  513.       length = nDegHalf*gi.nScale;
  514.       if (gs.yWin != length) {
  515.         gs.yWin = length;
  516.         fResize = fTrue;
  517.       }
  518.     } else if (gi.nMode == gGrid) {
  519.       if (gs.xWin != (length =
  520.         (gs.nGridCell + (us.nRel <= rcDual))*CELLSIZE*gi.nScale+1)) {
  521.         gs.xWin = length;
  522.         fResize = fTrue;
  523.       } if (gs.yWin != length) {
  524.         gs.yWin = length;
  525.         fResize = fTrue;
  526.       }
  527.  
  528.     /* Make sure the window isn't too large or too small. */
  529.  
  530.     } else {
  531.       if (gs.xWin < BITMAPX1) {
  532.         gs.xWin = BITMAPX1;
  533.         fResize = fTrue;
  534.       } else if (gs.xWin > BITMAPX) {
  535.         gs.xWin = BITMAPX;
  536.         fResize = fTrue;
  537.       }
  538.       if (gs.yWin < BITMAPY1) {
  539.         gs.yWin = BITMAPY1;
  540.         fResize = fTrue;
  541.       } else if (gs.yWin > BITMAPY) {
  542.         gs.yWin = BITMAPY;
  543.         fResize = fTrue;
  544.       }
  545.     }
  546.  
  547.     /* If in animation mode, ensure we are in the flicker free resolution. */
  548.  
  549.     if (gs.nAnim < 0) {
  550.       neg(gs.nAnim);
  551. #ifdef PCG
  552.       if (gi.nRes == gs.nResHi && !gs.fJetTrail) {
  553.         gi.nRes = gs.nResLo;
  554.         BeginX();
  555.         gs.xWin = xPcScreen;
  556.         gs.yWin = yPcScreen;
  557.         SquareX(&gs.xWin, &gs.yWin, fFalse);
  558.         fResize = fTrue;
  559.       }
  560. #endif
  561.     }
  562.  
  563.     /* Physically resize window if we've changed the size parameters. */
  564.  
  565.     if (fResize) {
  566.       fResize = fFalse;
  567. #ifdef X11
  568.       XResizeWindow(gi.disp, gi.wind, gs.xWin, gs.yWin);
  569.       XFreePixmap(gi.disp, gi.pmap);
  570.       gi.pmap = XCreatePixmap(gi.disp, gi.wind, gs.xWin, gs.yWin, gi.depth);
  571. #else
  572.       if (xPcScreen > gs.xWin)
  573.         gi.xOffset = (xPcScreen - gs.xWin) / 2;
  574.       else {
  575.         if (xcorner % 3 == 1)
  576.           gi.xOffset = 0;
  577.         else if (xcorner % 3 == 0)
  578.           gi.xOffset = -gs.xWin + xPcScreen;
  579.         else
  580.           gi.xOffset = -(gs.xWin - xPcScreen) / 2;
  581.       }
  582.       if (yPcScreen > gs.yWin)
  583.         gi.yOffset = (yPcScreen - gs.yWin) / 2;
  584.       else {
  585.         if (xcorner > 6)
  586.           gi.yOffset = 0;
  587.         else if (xcorner < 4)
  588.           gi.yOffset = -gs.yWin + yPcScreen;
  589.         else
  590.           gi.yOffset = -(gs.yWin - yPcScreen) / 2;
  591.       }
  592. #endif
  593.       fRedraw = fTrue;
  594.     }
  595.  
  596.     /* Recast chart if the chart information has changed any. */
  597.  
  598.     if (fCast) {
  599.       fCast = fFalse;
  600.       ciCore = ciMain;
  601.       if (us.nRel)
  602.         CastRelation(fFalse);
  603.       else
  604.         CastChart(fTrue);
  605.       fRedraw = fTrue;
  606.     }
  607.     if (gs.nAnim && !fPause)
  608.       fRedraw = fTrue;
  609.  
  610.     /* Update the screen if anything has changed since last time around. */
  611.  
  612.     if (fRedraw) {
  613.       fRedraw = fFalse;
  614.  
  615.       /* If we're in animation mode, change the chart info appropriately. */
  616.  
  617.       if (gs.nAnim && !fPause)
  618.         Animate(gs.nAnim, dir);
  619.  
  620.       /* Clear the screen and set up a buffer to draw in. */
  621.  
  622. #ifdef X11
  623.       XFillRectangle(gi.disp, gi.pmap, gi.pmgc, 0, 0, gs.xWin, gs.yWin);
  624. #else /* PCG */
  625. #ifdef MOUSE
  626.       MouseShow(fFalse);
  627. #endif
  628. #ifdef MSG
  629.       if (gi.cfg.numvideopages > 1)
  630.         _setactivepage(_getactivepage() == gs.fJetTrail);
  631. #else
  632.       if (gi.nPages > 1) {
  633.         gi.nPageCur = (gi.nPageCur == gs.fJetTrail);
  634.         setactivepage(gi.nPageCur);
  635.       }
  636. #endif
  637. #endif /* PCG */
  638.  
  639.       DrawChartX();
  640.  
  641.       /* Make the drawn chart visible in the current screen buffer. */
  642.  
  643. #ifdef X11
  644.       XSync(gi.disp, 0);
  645.       XCopyArea(gi.disp, gi.pmap, gi.wind, gi.gc,
  646.         0, 0, gs.xWin, gs.yWin, 0, 0);
  647. #else /* PCG */
  648. #ifdef MSG
  649.       if (gi.cfg.numvideopages > 1)
  650.         _setvisualpage(_getactivepage());
  651. #else
  652.       if (gi.nPages > 1)
  653.         setvisualpage(gi.nPageCur);
  654. #endif
  655. #ifdef MOUSE
  656.       if (!gs.nAnim || fPause)
  657.         MouseShow(fTrue);
  658. #endif
  659. #endif /* PCG */
  660.     }  /* if */
  661.  
  662.     /* Now process what's on the event queue, i.e. any keys pressed, etc. */
  663.  
  664. #ifdef X11
  665.     if (XEventsQueued(gi.disp, QueuedAfterFlush /*QueuedAfterReading*/) ||
  666.       !gs.nAnim || fPause) {
  667.       XNextEvent(gi.disp, &xevent);
  668.  
  669.       /* Restore what's on window if a part of it gets uncovered. */
  670.  
  671.       if (xevent.type == Expose && xevent.xexpose.count == 0) {
  672.         XSync(gi.disp, 0);
  673.         XCopyArea(gi.disp, gi.pmap, gi.wind, gi.gc,
  674.           0, 0, gs.xWin, gs.yWin, 0, 0);
  675.       }
  676.       switch (xevent.type) {
  677.  
  678.       /* Check for a manual resize of window by user. */
  679.  
  680.       case ConfigureNotify:
  681.         gs.xWin = xevent.xconfigure.width;
  682.         gs.yWin = xevent.xconfigure.height;
  683.         XFreePixmap(gi.disp, gi.pmap);
  684.         gi.pmap = XCreatePixmap(gi.disp, gi.wind, gs.xWin, gs.yWin, gi.depth);
  685.         fRedraw = fTrue;
  686.         break;
  687.       case MappingNotify:
  688.         XRefreshKeyboardMapping((XMappingEvent *)&xevent);
  689.         break;
  690.  
  691. #ifdef MOUSE
  692.       /* Process any mouse buttons the user pressed. */
  693.  
  694.       case ButtonPress:
  695.         mousex = xevent.xbutton.x; mousey = xevent.xbutton.y;
  696.         if (xevent.xbutton.button == Button1) {
  697.           DrawColor(gi.kiLite);
  698.           DrawPoint(mousex, mousey);
  699.           XSync(gi.disp, 0);
  700.           XCopyArea(gi.disp, gi.pmap, gi.wind, gi.gc,
  701.             0, 0, gs.xWin, gs.yWin, 0, 0);
  702.         } else if (xevent.xbutton.button == Button2 && (gi.nMode ==
  703.           gAstroGraph || gi.nMode == gWorldMap) && gs.nRot == 0) {
  704.           Lon = DegToDec(rDegHalf -
  705.             (real)(xevent.xbutton.x-1)/(real)(gs.xWin-2)*rDegMax);
  706.           Lat = DegToDec(rDegQuad -
  707.             (real)(xevent.xbutton.y-1)/(real)(gs.yWin-2)*181.0);
  708.           sprintf(sz, "Mouse is at %s.", SzLocation(Lon, Lat));
  709.           PrintNotice(sz);
  710.         } else if (xevent.xbutton.button == Button3)
  711.           fBreak = fTrue;
  712.         break;
  713.  
  714.       /* Check for user dragging any of the mouse buttons across window. */
  715.  
  716.       case MotionNotify:
  717.         DrawColor(coldrw);
  718.         DrawLine(mousex, mousey, xevent.xbutton.x, xevent.xbutton.y);
  719.         XSync(gi.disp, 0);
  720.         XCopyArea(gi.disp, gi.pmap, gi.wind, gi.gc,
  721.           0, 0, gs.xWin, gs.yWin, 0, 0);
  722.         mousex = xevent.xbutton.x; mousey = xevent.xbutton.y;
  723.         break;
  724. #endif
  725.  
  726.       /* Process any keys user pressed in window. */
  727.  
  728.       case KeyPress:
  729.         length = XLookupString((XKeyEvent *)&xevent, xkey, 10, &keysym, 0);
  730.         if (length == 1) {
  731.           key = xkey[0];
  732. #else /* PCG */
  733. #ifdef MOUSE
  734.       if ((!gs.nAnim || fPause) && MouseStatus(&eventx, &eventy, &eventbtn)) {
  735.  
  736.         /* If the left button is down, draw on the screen. */
  737.         if (eventbtn == mfLeft && mousex >= 0) {
  738.           MouseShow(fFalse);
  739.           DrawColor(coldrw);
  740.           PcMoveTo(mousex, mousey);
  741.           buttonx = eventx; buttony = eventy;
  742.           PcLineTo(buttonx, buttony);
  743.  
  744.         /* If the right button is down, change the default location. */
  745.         } else if (eventbtn == mfRight) {
  746.           if (fMap && gs.nRot == 0 && !gs.fConstel && !gs.fMollewide) {
  747.             Lon = rDegHalf-(real)(eventx-gi.xOffset)/(real)(gs.xWin-2)*rDegMax;
  748.             if (Lon < -rDegHalf)
  749.               Lon = -rDegHalf;
  750.             else if (Lon > rDegHalf)
  751.               Lon = rDegHalf;
  752.             Lat =  rDegQuad-(real)(eventy-gi.yOffset)/(real)(gs.yWin-2)*181.0;
  753.             if (Lat < -rDegQuad)
  754.               Lat = -rDegQuad;
  755.             else if (Lat > rDegQuad)
  756.               Lat = rDegQuad;
  757.             fCast = fTrue;
  758.  
  759.           /* Right button means draw lines if not in a world map mode. */
  760.           } else if (buttonx >= 0) {
  761.             MouseShow(fFalse);
  762.             DrawColor(coldrw);
  763.             PcMoveTo(buttonx, buttony);
  764.             PcLineTo(eventx, eventy);
  765.           }
  766.  
  767.         /* Middle button (which most PC's don't have) means exit program. */
  768.         } else if (eventbtn == mfMiddle)
  769.           fBreak = fTrue;
  770.  
  771.         mousex = eventx; mousey = eventy;
  772.         MouseShow(fTrue);
  773.       } else
  774. #endif /* MOUSE */
  775.         if (kbhit()) {
  776.           key = getch();
  777. #endif /* PCG */
  778. LSwitch:
  779.           switch (key) {
  780. #ifdef PCG
  781.           case chNull:
  782.             key = NFromAltN(getch());
  783.             goto LSwitch;
  784. #endif
  785.           case ' ':
  786.             fRedraw = fTrue;
  787.             break;
  788.           case 'p':
  789.             not(fPause);
  790.             break;
  791.           case 'r':
  792.             neg(dir);
  793.             break;
  794.           case 'x':
  795.             not(gs.fInverse);
  796.             InitColorsX();
  797.             fRedraw = fTrue;
  798.             break;
  799.           case 'm':
  800.             if (!gi.fMono) {
  801.               not(gs.fColor);
  802. #ifdef MSG
  803.               _getvideoconfig((struct videoconfig far *) &gi.cfg);
  804. #endif
  805.               InitColorsX();
  806.               fRedraw = fTrue;
  807.             }
  808.             break;
  809.           case 'B':
  810. #ifdef X11
  811.             XSetWindowBackgroundPixmap(gi.disp, gi.root, gi.pmap);
  812.             XClearWindow(gi.disp, gi.root);
  813. #else
  814.             gs.xWin = xPcScreen;
  815.             gs.yWin = yPcScreen;
  816.             SquareX(&gs.xWin, &gs.yWin, fFalse);
  817.             fResize = fTrue;
  818. #endif
  819.             break;
  820.           case 't':
  821.             not(gs.fText);
  822.             fRedraw = fTrue;
  823.             break;
  824.           case 'i':
  825.             not(gs.fAlt);
  826.             fRedraw = fTrue;
  827.             break;
  828.           case 'b':
  829.             not(gs.fBorder);
  830.             fRedraw = fTrue;
  831.             break;
  832.           case 'l':
  833.             not(gs.fLabel);
  834.             fRedraw = fTrue;
  835.             break;
  836.           case 'j':
  837.             not(gs.fJetTrail);
  838.             break;
  839.           case '<':
  840.             if (gs.nScale > 100) {
  841.               gs.nScale -= 100;
  842.               fResize = fTrue;
  843.             }
  844.             break;
  845.           case '>':
  846.             if (gs.nScale < 400) {
  847.               gs.nScale += 100;
  848.               fResize = fTrue;
  849.             }
  850.             break;
  851.           case '[':
  852.             if (gi.nMode == gGlobe && gs.rTilt > -rDegQuad) {
  853.               gs.rTilt = gs.rTilt > -rDegQuad ? gs.rTilt-11.25 : -rDegQuad;
  854.               fRedraw = fTrue;
  855.             }
  856.             break;
  857.           case ']':
  858.             if (gi.nMode == gGlobe && gs.rTilt < rDegQuad) {
  859.               gs.rTilt = gs.rTilt < rDegQuad ? gs.rTilt+11.25 : rDegQuad;
  860.               fRedraw = fTrue;
  861.             }
  862.             break;
  863.           case 'Q':
  864.             SquareX(&gs.xWin, &gs.yWin, fTrue);
  865.             fResize = fTrue;
  866.             break;
  867.           case 'R':
  868.             for (i = oChi; i <= oVes; i++)
  869.               not(ignore[i]);
  870.             for (i = oLil; i <= oEP; i++)
  871.               not(ignore[i]);
  872.             fCast = fTrue;
  873.             break;
  874.           case 'C':
  875.             not(us.fCusp);
  876.             for (i = cuspLo; i <= cuspHi; i++)
  877.               ignore[i] = !us.fCusp || !ignore[i];
  878.             fCast = fTrue;
  879.             break;
  880.           case 'u':
  881.             not(us.fUranian);
  882.             for (i = uranLo; i <= uranHi; i++)
  883.               ignore[i] = !us.fUranian || !ignore[i];
  884.             fCast = fTrue;
  885.             break;
  886.           case 'U':
  887.             us.nStar = !us.nStar;
  888.             for (i = starLo; i <= starHi; i++)
  889.               ignore[i] = !us.nStar || !ignore[i];
  890.             fCast = fTrue;
  891.             break;
  892.           case 'c':
  893.             if (!us.nRel) {
  894.               us.nRel = rcDual;
  895.               ciTwin = ciMain;
  896.             } else
  897.               us.nRel = 0;
  898.             fCast = fTrue;
  899.             break;
  900.           case 's':
  901.             not(us.fSiderial);
  902.             fCast = fTrue;
  903.             break;
  904.           case 'h':
  905.             us.objCenter = us.objCenter ? 0 : 1;
  906.             fCast = fTrue;
  907.             break;
  908.           case 'f':
  909.             not(us.fFlip);
  910.             fCast = fTrue;
  911.             break;
  912.           case 'g':
  913.             not(us.fDecan);
  914.             fCast = fTrue;
  915.             break;
  916.           case '+':
  917.             Animate(gs.nAnim, abs(dir));
  918.             fCast = fTrue;
  919.             break;
  920.           case '-':
  921.             Animate(gs.nAnim, -abs(dir));
  922.             fCast = fTrue;
  923.             break;
  924.           case 'o':
  925.             ciSave = ciMain;
  926.             break;
  927.           case 'O':
  928.             ciMain = ciSave;
  929.             fCast = fTrue;
  930.             break;
  931. #ifdef TIME
  932.           case 'n':
  933.             FInputData(szNowCore);
  934.             ciMain = ciCore;
  935.             fCast = fTrue;
  936.             break;
  937. #endif
  938.           case 'N':                     /* The continuous update animation. */
  939.             gs.nAnim = gs.nAnim ? 0 : -10;
  940.             break;
  941.  
  942.           /* These are the nine different "add time to chart" animations. */
  943.           case '!': gs.nAnim = -1; break;
  944.           case '@': gs.nAnim = -2; break;
  945.           case '#': gs.nAnim = -3; break;
  946.           case '$': gs.nAnim = -4; break;
  947.           case '%': gs.nAnim = -5; break;
  948.           case '^': gs.nAnim = -6; break;
  949.           case '&': gs.nAnim = -7; break;
  950.           case '*': gs.nAnim = -8; break;
  951.           case '(': gs.nAnim = -9; break;
  952.  
  953.           /* Should we go switch to a new chart type? */
  954.           case 'V': gi.nMode = gWheel;      fRedraw = fTrue; break;
  955.           case 'A': gi.nMode = gGrid;       fRedraw = fTrue; break;
  956.           case 'Z': gi.nMode = gHorizon;    fRedraw = fTrue; break;
  957.           case 'S': gi.nMode = gOrbit;      fRedraw = fTrue; break;
  958.           case 'J': gi.nMode = gDisposit;   fRedraw = fTrue; break;
  959.           case 'L': gi.nMode = gAstroGraph; fRedraw = fTrue; break;
  960.           case 'K': gi.nMode = gCalendar;   fRedraw = fTrue; break;
  961.           case 'E': gi.nMode = gEphemeris;  fRedraw = fTrue; break;
  962.           case 'W': gi.nMode = gWorldMap;   fRedraw = fTrue; break;
  963.           case 'G': gi.nMode = gGlobe;      fRedraw = fTrue; break;
  964.           case 'P': gi.nMode = gPolar;      fRedraw = fTrue; break;
  965. #ifdef BIORHYTHM
  966.           case 'Y':            /* Should we switch to biorhythm chart? */
  967.             if (!us.nRel)
  968.               ciTwin = ciMain;
  969.             us.nRel = rcBiorhythm;
  970.             gi.nMode = gBiorhythm;
  971.             fCast = fTrue;
  972.             break;
  973. #endif
  974. #ifdef CONSTEL
  975.           case 'F':
  976.             if (!fMap && gi.nMode != gGlobe && gi.nMode != gPolar)
  977.               gi.nMode = gWorldMap;
  978.             not(gs.fConstel);
  979.             fRedraw = fTrue;
  980.             break;
  981. #endif
  982.           case '0':
  983.             not(us.fPrimeVert);
  984.             not(us.fCalendarYear);
  985.             not(us.nEphemYears);
  986.             not(gs.fMollewide);
  987.             gi.nMode = (gi.nMode == gWheel ? gHouse :
  988.               (gi.nMode == gHouse ? gWheel : gi.nMode));
  989.             fRedraw = fTrue;
  990.             break;
  991.           case 'v': case 'H': case '?':
  992. #ifdef MSG
  993.             _setvideomode(_DEFAULTMODE);
  994.             if (key != 'v')
  995.               _settextrows(50);
  996. #endif
  997. #ifdef BGI
  998.             restorecrtmode();
  999.             if (key != 'v')
  1000.               textmode(C4350);
  1001. #endif
  1002.             length = us.nScrollRow;
  1003.             us.nScrollRow = 0;
  1004.             if (key == 'v')
  1005.               ChartListing();
  1006.             else
  1007.               DisplayKeysX();
  1008.             us.nScrollRow = length;
  1009. #ifdef PCG
  1010.             while (!kbhit())
  1011.               ;
  1012.             key = getch();
  1013.             if (key == 'q' || key == chEscape || key == chBreak) {
  1014.               fBreak = fTrue;
  1015.               break;
  1016.             }
  1017.             BeginX();
  1018.             fResize = fTrue;
  1019. #endif
  1020.             break;
  1021.           case chReturn:
  1022.             CommandLineX();
  1023.             fResize = fCast = fTrue;
  1024.             break;
  1025. #ifdef PCG
  1026.           case chTab:
  1027.             if (gi.nRes == gs.nResHi)
  1028.               gi.nRes = gs.nResLo;
  1029.             else
  1030.               gi.nRes = gs.nResHi;
  1031.             BeginX();
  1032.             gs.xWin = xPcScreen;
  1033.             gs.yWin = yPcScreen;
  1034.             SquareX(&gs.xWin, &gs.yWin, fFalse);
  1035.             fResize = fTrue;
  1036.             break;
  1037. #endif
  1038.           case chDelete:
  1039. #ifdef PCG
  1040. #ifdef MOUSE
  1041.             MouseShow(fFalse);
  1042. #endif
  1043. #endif /* PCG */
  1044.             fT = gs.fJetTrail;
  1045.             gs.fJetTrail = fFalse;
  1046.             DrawClearScreen();
  1047.             gs.fJetTrail = fT;
  1048.             break;
  1049. #ifdef MOUSE
  1050.           case 'z'-'`': coldrw = kBlack;   break;
  1051.           case 'e'-'`': coldrw = kMaroon;  break;
  1052.           case 'f'-'`': coldrw = kDkGreen; break;
  1053.           case 'o'-'`': coldrw = kOrange;  break;
  1054.           case 'n'-'`': coldrw = kDkBlue;  break;
  1055.           case 'u'-'`': coldrw = kPurple;  break;
  1056.           case 'k'-'`': coldrw = kDkCyan;  break;
  1057.           case 'l'-'`': coldrw = kLtGray;  break;
  1058.           case 'd'-'`': coldrw = kDkGray;  break;
  1059.           case 'r'-'`': coldrw = kRed;     break;
  1060.           case 'g'-'`': coldrw = kGreen;   break;
  1061.           case 'y'-'`': coldrw = kYellow;  break;
  1062.           case 'b'-'`': coldrw = kBlue;    break;
  1063.           case 'v'-'`': coldrw = kMagenta; break;
  1064.           case 'j'-'`': coldrw = kCyan;    break;
  1065.           case 'a'-'`': coldrw = kWhite;   break;
  1066. #ifdef PCG
  1067.           case 't'-'`':
  1068.             MouseShow(fFalse);
  1069.             if (buttonx >= 0)
  1070. #ifdef MSG
  1071.               _rectangle(_GBORDER, buttonx, buttony, mousex, mousey);
  1072. #else
  1073.               DrawEdge(Min(buttonx, mousex) - gi.xOffset,
  1074.                 Min(buttony, mousey) - gi.yOffset,
  1075.                 Max(mousex, buttonx) - gi.xOffset,
  1076.                 Max(mousey, buttony) - gi.yOffset);
  1077. #endif
  1078.             MouseShow(fTrue);
  1079.             break;
  1080.           case 'x'-'`':
  1081.             MouseShow(fFalse);
  1082.             if (buttonx >= 0)
  1083. #ifdef MSG
  1084.               _ellipse(_GBORDER, buttonx, buttony, mousex, mousey);
  1085. #else
  1086.               DrawEllipse(Min(buttonx, mousex) - gi.xOffset,
  1087.                 Min(buttony, mousey) - gi.yOffset,
  1088.                 Max(mousex, buttonx) - gi.xOffset,
  1089.                 Max(mousey, buttony) - gi.yOffset);
  1090. #endif
  1091.             MouseShow(fTrue);
  1092.             break;
  1093. #endif /* PCG */
  1094. #endif /* MOUSE */
  1095.           case 'q': case chEscape: case chBreak:
  1096.             fBreak = fTrue;
  1097.             break;
  1098.           default:
  1099.             if (key > '0' && key <= '9') {
  1100. #ifdef PCG
  1101.               if (gs.nAnim && !fPause)
  1102. #endif
  1103.                 /* Process numbers 1..9 signifying animation rate. */
  1104.                 dir = (dir > 0 ? 1 : -1)*(key-'0');
  1105. #ifdef PCG
  1106.               else {
  1107.                 /* If we aren't in animation mode, then 1..9 refers to the */
  1108.                 /* clipping "quadrant" to use if chart size > screen size. */
  1109.                 xcorner = key-'0';
  1110.                 fResize = fTrue;
  1111.               }
  1112. #endif
  1113.               break;
  1114.             } else if (FBetween(key, 201, 248)) {
  1115.               is.fSzInteract = fTrue;
  1116.               if (szMacro[key-201]) {
  1117.                 FProcessCommandLine(szMacro[key-201]);
  1118.                 fResize = fCast = fTrue;
  1119.               }
  1120.               is.fSzInteract = fFalse;
  1121.               break;
  1122.             }
  1123.             putchar(chBell);    /* Any key not bound will sound a beep. */
  1124.           }  /* switch */
  1125.         }  /* if */
  1126. #ifdef X11
  1127.       default:
  1128.         ;
  1129.       }  /* switch */
  1130.     }  /* if */
  1131. #endif
  1132.   }  /* while */
  1133. }
  1134.  
  1135.  
  1136. /* This is called right before program termination to get rid of the window. */
  1137.  
  1138. void EndX()
  1139. {
  1140. #ifdef X11
  1141.   XFreeGC(gi.disp, gi.gc);
  1142.   XFreeGC(gi.disp, gi.pmgc);
  1143.   XFreePixmap(gi.disp, gi.pmap);
  1144.   XDestroyWindow(gi.disp, gi.wind);
  1145.   XCloseDisplay(gi.disp);
  1146. #endif
  1147. #ifdef MSG
  1148.   _setvideomode(_DEFAULTMODE);
  1149. #endif
  1150. #ifdef BGI
  1151.   restorecrtmode();
  1152. #endif
  1153. }
  1154. #endif /* ISG */
  1155.  
  1156.  
  1157. /*
  1158. ******************************************************************************
  1159. ** Main Graphics Processing.
  1160. ******************************************************************************
  1161. */
  1162.  
  1163. /* Process one command line switch passed to the program dealing with the    */
  1164. /* graphics features. This is just like the processing of each switch in the */
  1165. /* main program, however here each switch has been prefixed with an 'X'.     */
  1166.  
  1167. int NProcessSwitchesX(argc, argv, pos, fOr, fAnd, fNot)
  1168. int argc, pos;
  1169. bool fOr, fAnd, fNot;
  1170. char **argv;
  1171. {
  1172.   int darg = 0, i, j;
  1173.   real rT;
  1174.   char ch1;
  1175.  
  1176.   ch1 = argv[0][pos+1];
  1177.   switch (argv[0][pos]) {
  1178.   case chNull:
  1179.     break;
  1180.  
  1181.   case 'b':
  1182.     if (is.fSzInteract) {
  1183.       ErrorArgv("Xb");
  1184.       return tcError;
  1185.     }
  1186.     ch1 = ChCap(ch1);
  1187.     if (FValidBmpmode(ch1))
  1188.       gs.chBmpMode = ch1;
  1189.     SwitchF2(gs.fBitmap);
  1190.     gs.fPS = gs.fMeta = fFalse;
  1191.     break;
  1192.  
  1193. #ifdef PS
  1194.   case 'p':
  1195.     if (is.fSzInteract) {
  1196.       ErrorArgv("Xp");
  1197.       return tcError;
  1198.     }
  1199.     gs.fPS = fTrue + (ch1 != '0');
  1200.     gs.fBitmap = gs.fMeta = fFalse;
  1201.     break;
  1202. #endif
  1203.  
  1204. #ifdef META
  1205.   case 'M':
  1206.     if (is.fSzInteract) {
  1207.       ErrorArgv("XM");
  1208.       return tcError;
  1209.     }
  1210.     if (ch1 == '0')
  1211.       SwitchF(gs.fFont);
  1212.     SwitchF2(gs.fMeta);
  1213.     gs.fBitmap = gs.fPS = fFalse;
  1214.     break;
  1215. #endif
  1216.  
  1217.   case 'o':
  1218.     if (is.fSzInteract) {
  1219.       ErrorArgv("Xo");
  1220.       return tcError;
  1221.     }
  1222.     if (argc <= 1) {
  1223.       ErrorArgc("Xo");
  1224.       return tcError;
  1225.     }
  1226.     if (!gs.fBitmap && !gs.fPS && !gs.fMeta)
  1227.       gs.fBitmap = fTrue;
  1228.     gi.szFileOut = SzPersist(argv[1]);
  1229.     darg++;
  1230.     break;
  1231.  
  1232. #ifdef X11
  1233.   case 'B':
  1234.     if (is.fSzInteract) {
  1235.       ErrorArgv("XB");
  1236.       return tcError;
  1237.     }
  1238.     SwitchF(gs.fRoot);
  1239.     break;
  1240. #endif
  1241.  
  1242.   case 'm':
  1243.     SwitchF(gs.fColor);
  1244.     break;
  1245.  
  1246.   case 'r':
  1247.     SwitchF(gs.fInverse);
  1248.     break;
  1249.  
  1250.   case 'w':
  1251.     if (argc <= 1) {
  1252.       ErrorArgc("Xw");
  1253.       return tcError;
  1254.     }
  1255.     i = atoi(argv[1]);
  1256.     if (argc > 2 && ((j = atoi(argv[2])) || argv[2][0] == '0')) {
  1257.       argc--; argv++;
  1258.       darg++;
  1259.     } else
  1260.       j = i;
  1261.     if (!FValidGraphx(i)) {
  1262.       ErrorValN("Xw", i);
  1263.       return tcError;
  1264.     }
  1265.     if (!FValidGraphy(j)) {
  1266.       ErrorValN("Xw", j);
  1267.       return tcError;
  1268.     }
  1269.     gs.xWin = i; gs.yWin = j;
  1270.     darg++;
  1271.     break;
  1272.  
  1273.   case 's':
  1274.     if (argc <= 1) {
  1275.       ErrorArgc("Xs");
  1276.       return tcError;
  1277.     }
  1278.     i = atoi(argv[1]);
  1279.     if (i < 100)
  1280.       i *= 100;
  1281.     if (!FValidScale(i)) {
  1282.       ErrorValN("Xs", i);
  1283.       return tcError;
  1284.     }
  1285.     gs.nScale = i;
  1286.     darg++;
  1287.     break;
  1288.  
  1289.   case 'i':
  1290.     SwitchF(gs.fAlt);
  1291.     break;
  1292.  
  1293.   case 't':
  1294.     SwitchF(gs.fText);
  1295.     break;
  1296.  
  1297.   case 'u':
  1298.     SwitchF(gs.fBorder);
  1299.     break;
  1300.  
  1301.   case 'l':
  1302.     SwitchF(gs.fLabel);
  1303.     break;
  1304.  
  1305.   case 'j':
  1306.     SwitchF(gs.fJetTrail);
  1307.     break;
  1308.  
  1309.   case '1':
  1310.     if (argc <= 1) {
  1311.       ErrorArgc("X1");
  1312.       return tcError;
  1313.     }
  1314.     i = atoi(argv[1]);
  1315.     if (!FItem(i)) {
  1316.       ErrorValN("X1", i);
  1317.       return tcError;
  1318.     }
  1319.     gs.nLeft = i;
  1320.     darg++;
  1321.     break;
  1322.  
  1323.   case '2':
  1324.     if (argc <= 1) {
  1325.       ErrorArgc("X2");
  1326.       return tcError;
  1327.     }
  1328.     i = atoi(argv[1]);
  1329.     if (!FItem(i)) {
  1330.       ErrorValN("X2", i);
  1331.       return tcError;
  1332.     }
  1333.     gs.nLeft = -i;
  1334.     darg++;
  1335.     break;
  1336.  
  1337.   case 'd':
  1338.     if (is.fSzInteract) {
  1339.       ErrorArgv("Xd");
  1340.       return tcError;
  1341.     }
  1342.     if (argc <= 1) {
  1343.       ErrorArgc("Xd");
  1344.       return tcError;
  1345.     }
  1346.     gs.szDisplay = SzPersist(argv[1]);
  1347.     darg++;
  1348.     break;
  1349.  
  1350.   case 'W':
  1351.     if (argc > 1 && ((i = atoi(argv[1])) || argv[1][0] == '0')) {
  1352.       darg++;
  1353.       if (!FValidRotation(i)) {
  1354.         ErrorValN("XW", i);
  1355.         return tcError;
  1356.       }
  1357.       gs.nRot = i;
  1358.     }
  1359.     gi.nMode = gWorldMap;
  1360.     if (ch1 == '0')
  1361.       gs.fMollewide = fTrue;
  1362.     is.fHaveInfo = fTrue;
  1363.     break;
  1364.  
  1365.   case 'G':
  1366.     if (argc > 1 && ((i = atoi(argv[1])) || argv[1][0] == '0')) {
  1367.       darg++;
  1368.       if (!FValidRotation(i)) {
  1369.         ErrorValN("XG", i);
  1370.         return tcError;
  1371.       }
  1372.       gs.nRot = i;
  1373.       if (argc > 2 && ((rT = atof(argv[2])) || argv[2][0] == '0')) {
  1374.         darg++;
  1375.         if (!FValidTilt(rT)) {
  1376.           ErrorValR("XG", rT);
  1377.           return tcError;
  1378.         }
  1379.         gs.rTilt = rT;
  1380.       }
  1381.     }
  1382.     gi.nMode = gGlobe;
  1383.     is.fHaveInfo = fTrue;
  1384.     break;
  1385.  
  1386.   case 'P':
  1387.     if (argc > 1 && ((i = atoi(argv[1])) || argv[1][0] == '0')) {
  1388.       darg++;
  1389.       if (!FValidRotation(i)) {
  1390.         ErrorValN("XP", i);
  1391.         return tcError;
  1392.       }
  1393.     } else
  1394.       i = 0;
  1395.     gs.nRot = i;
  1396.     gi.nMode = gPolar;
  1397.     if (ch1 == '0')
  1398.       gs.fPrintMap = fTrue;
  1399.     is.fHaveInfo = fTrue;
  1400.     break;
  1401.  
  1402. #ifdef CONSTEL
  1403.   case 'F':
  1404.     if (!fMap && gi.nMode != gGlobe && gi.nMode != gPolar)
  1405.       gi.nMode = gWorldMap;
  1406.     not(gs.fConstel);
  1407.     is.fHaveInfo = fTrue;
  1408.     break;
  1409. #endif
  1410.  
  1411. #ifdef ISG
  1412.   case 'n':
  1413.     if (argc > 1 && (i = atoi(argv[1])))
  1414.       darg++;
  1415.     else
  1416.       i = 10;
  1417.     if (i < 1 || i > 10) {
  1418.       ErrorValN("Xn", i);
  1419.       return tcError;
  1420.     }
  1421.     gs.nAnim = i;
  1422.     break;
  1423. #endif
  1424.  
  1425.   default:
  1426.     ErrorSwitch(argv[0]);
  1427.     return tcError;
  1428.   }
  1429.   /* 'darg' contains the value to be added to argc when we return. */
  1430.   return darg;
  1431. }
  1432.  
  1433.  
  1434. /* Process one command line switch passed to the program dealing with more  */
  1435. /* obscure graphics options. This is structured very much like the function */
  1436. /* NProcessSwitchesX(), except here we know each switch begins with 'YX'.   */
  1437.  
  1438. int NProcessSwitchesRareX(argc, argv, pos)
  1439. int argc, pos;
  1440. char **argv;
  1441. {
  1442.   int darg = 0, i, j;
  1443.   char ch1;
  1444.  
  1445.   ch1 = argv[0][pos+1];
  1446.   switch (argv[0][pos]) {
  1447.   case chNull:
  1448.     if (argc <= 2) {
  1449.       ErrorArgc("YX");
  1450.       return tcError;
  1451.     }
  1452. #ifdef PCG
  1453.     i = atoi(argv[1]);
  1454.     if (!FValidResmode(i)) {
  1455.       ErrorValN("YX", i);
  1456.       return tcError;
  1457.     }
  1458.     gs.nResHi = i;
  1459.     i = atoi(argv[2]);
  1460.     if (!FValidResmode(i)) {
  1461.       ErrorValN("YX", i);
  1462.       return tcError;
  1463.     }
  1464.     gs.nResLo = i;
  1465.     gs.fBitmap = gs.fPS = gs.fMeta = fFalse;
  1466. #endif
  1467.     darg += 2;
  1468.     break;
  1469.  
  1470.   case 'G':
  1471.     if (argc <= 1) {
  1472.       ErrorArgc("YXG");
  1473.       return tcError;
  1474.     }
  1475.     i = atoi(argv[1]);
  1476.     if (!FValidGlyphs(i)) {
  1477.       ErrorValN("YXg", i);
  1478.       return tcError;
  1479.     }
  1480.     gs.nGlyphs = i;
  1481.     j = i/1000;
  1482.     if (FBetween(j, 1, 2))
  1483.       szDrawSign[sCap] = szDrawSign[cSign+j];
  1484.     j = (i/100)%10;
  1485.     if (FBetween(j, 1, 2))
  1486.       szDrawObject[oUra] = szDrawObject[oNorm+j];
  1487.     j = (i/10)%10;
  1488.     if (FBetween(j, 1, 2))
  1489.       szDrawObject[oPlu] = szDrawObject[oNorm+2+j];
  1490.     j = i%10;
  1491.     if (FBetween(j, 1, 3))
  1492.       szDrawObject[oLil] = szDrawObject[oNorm+4+j];
  1493.     darg++;
  1494.     break;
  1495.  
  1496.   case 'g':
  1497.     if (argc <= 1) {
  1498.       ErrorArgc("YXg");
  1499.       return tcError;
  1500.     }
  1501.     i = atoi(argv[1]);
  1502.     if (!FValidGrid(i)) {
  1503.       ErrorValN("YXg", i);
  1504.       return tcError;
  1505.     }
  1506.     gs.nGridCell = i;
  1507.     darg++;
  1508.     break;
  1509.  
  1510.   case 'f':
  1511.     if (argc <= 1) {
  1512.       ErrorArgc("YXf");
  1513.       return tcError;
  1514.     }
  1515.     gs.fFont = atoi(argv[1]);
  1516.     darg++;
  1517.     break;
  1518.  
  1519. #ifdef PS
  1520.   case 'p':
  1521.     if (ch1 == '0') {
  1522.       if (argc <= 2) {
  1523.         ErrorArgc("YXp0");
  1524.         return tcError;
  1525.       }
  1526.       gs.xInch = atof(argv[1]);
  1527.       gs.yInch = atof(argv[2]);
  1528.       darg += 2;
  1529.       break;
  1530.     }
  1531.     if (argc <= 1) {
  1532.       ErrorArgc("YXp");
  1533.       return tcError;
  1534.     }
  1535.     gs.nOrient = atoi(argv[1]);
  1536.     darg++;
  1537.     break;
  1538. #endif
  1539.  
  1540.   default:
  1541.     ErrorSwitch(argv[0]);
  1542.     return tcError;
  1543.   }
  1544.   /* 'darg' contains the value to be added to argc when we return. */
  1545.   return darg;
  1546. }
  1547.  
  1548.  
  1549. /* This is the main interface to all the graphics features. This routine     */
  1550. /* is called from the main program if any of the -X switches were specified, */
  1551. /* and it sets up for and goes and generates the appropriate graphics chart. */
  1552. /* We return fTrue if successfull, fFalse if some non-fatal error occurred.  */
  1553.  
  1554. bool FActionX()
  1555. {
  1556.   int i;
  1557.  
  1558.   /* Set up variables in preparation for graphics. Set the glyphs for     */
  1559.   /* certain objects to point to their current setting, and if doing      */
  1560.   /* constellations, give a couple stars more correct astronomical names. */
  1561.  
  1562. #ifdef CONSTEL
  1563.   if (gs.fConstel) {
  1564.     szObjName[starLo-1+10] = "Alnilam";  /* Normally "Orion"     */
  1565.     szObjName[starLo-1+47] = "M31";      /* Normally "Andromeda" */
  1566.   }
  1567. #endif
  1568.   i = gs.nGlyphs/1000;
  1569.   szDrawSign[sCap] = szDrawSign[cSign+(i == 2 ? 2 : 1)];
  1570.   i = (gs.nGlyphs/100)%10;
  1571.   szDrawObject[oUra] = szDrawObject[oNorm+(i == 2 ? 2 : 1)];
  1572.   i = (gs.nGlyphs/10)%10;
  1573.   szDrawObject[oPlu] = szDrawObject[oNorm+2+(i == 2 ? 2 : 1)];
  1574.   i = gs.nGlyphs%10;
  1575.   szDrawObject[oLil] =
  1576.     szDrawObject[oNorm+4+(FBetween(i, 2, 3) ? i : fSouthNode ? 3 : 1)];
  1577.   if (fSouthNode)
  1578.     szObjectFont[oSou] = '>';
  1579.   gi.fFile = (gs.fBitmap || gs.fPS || gs.fMeta);
  1580. #ifdef PS
  1581.   gi.fEps = gs.fPS > fTrue;
  1582. #endif
  1583.  
  1584.   /* First figure out what graphic mode to generate the chart in, based on */
  1585.   /* various non-X command switches, e.g. -L combined with -X, -g combined */
  1586.   /* with -X, and so on, and determine the size the window is to be, too.  */
  1587.  
  1588.   if (gi.nMode == gWheel) {
  1589.     if (us.fWheel)
  1590.       gi.nMode = gHouse;
  1591.     else if (us.fGrid || us.fMidpoint) {
  1592.       gi.nMode = gGrid;
  1593.       if (us.nRel <= rcDual && us.fMidpoint && !us.fAspList)
  1594.         us.fGridConfig = fTrue;
  1595.       gs.xWin = gs.yWin =
  1596.         (gs.nGridCell + (us.nRel <= rcDual))*CELLSIZE*gi.nScale + 1;
  1597.     } else if (us.fHorizon)
  1598.       gi.nMode = gHorizon;
  1599.     else if (us.fOrbit)
  1600.       gi.nMode = gOrbit;
  1601.     else if (us.fInfluence)
  1602.       gi.nMode = gDisposit;
  1603.     else if (us.fAstroGraph)
  1604.       gi.nMode = gAstroGraph;
  1605.     else if (us.fCalendar)
  1606.       gi.nMode = gCalendar;
  1607.     else if (us.fEphemeris)
  1608.       gi.nMode = gEphemeris;
  1609.     else if (us.nRel == rcBiorhythm)
  1610.       gi.nMode = gBiorhythm;
  1611.   }
  1612.   if (fMap) {
  1613.     gs.xWin = nDegMax*gi.nScale;
  1614.     gs.yWin = nDegHalf*gi.nScale;
  1615.   }
  1616.   gi.nScaleT = gs.fPS ? PSMUL : (gs.fMeta ? METAMUL : 1);
  1617.  
  1618.   if (gi.fFile) {
  1619.     if (gs.xWin == 0)
  1620.       gs.xWin = DEFAULTX;
  1621.     if (gs.yWin == 0)
  1622.       gs.yWin = DEFAULTY;
  1623.     if (fSidebar)
  1624.       gs.xWin += SIDESIZE;
  1625.     if (gs.xWin > BITMAPX)
  1626.       gs.xWin = BITMAPX;
  1627.     if (gs.yWin > BITMAPY)
  1628.       gs.yWin = BITMAPY;
  1629.     BeginFileX();
  1630.     if (gs.fBitmap) {
  1631.       gi.cbBmpRow = (gs.xWin + 1) >> 1;
  1632.       gi.yBand = gs.yWin;
  1633.       if (!FEnsureGrid())
  1634.         return fFalse;
  1635.       while ((gi.bm = PAllocate((long)gi.cbBmpRow * gi.yBand, fTrue, NULL)) ==
  1636.         NULL) {
  1637.         PrintWarning("The bitmap must be generated in multiple stages.");
  1638.         gi.yBand = (gi.yBand + 1) / 2;
  1639.         if (gi.yBand < 1 || gs.chBmpMode != 'B')
  1640.           return fFalse;
  1641.       }
  1642.       if (gi.yBand == gs.yWin)
  1643.         gi.yBand = 0;
  1644.       else {
  1645.         gi.yOffset = gs.yWin - gs.yWin % gi.yBand;
  1646.         if (gi.yOffset == gs.yWin)
  1647.           gi.yOffset -= gi.yBand;
  1648.       }
  1649.     }
  1650. #ifdef PS
  1651.     else if (gs.fPS)
  1652.       PsBegin();
  1653. #endif
  1654. #ifdef META
  1655.     else {
  1656.       if (!FEnsureGrid())
  1657.         return fFalse;
  1658.       for (gi.cbMeta = MAXMETA; gi.cbMeta > 0 &&
  1659.         (gi.bm = PAllocate(gi.cbMeta, fTrue, NULL)) == NULL;
  1660.         gi.cbMeta -= MAXMETA/8)
  1661.         PrintWarning("Attempting to get maximum memory for metafile.");
  1662.       if (gi.cbMeta == 0)
  1663.         return fFalse;
  1664.       gs.xWin   *= METAMUL;  /* Increase chart sizes and scales behind the */
  1665.       gs.yWin   *= METAMUL;  /* scenes to make graphics look smoother.     */
  1666.       gs.nScale *= METAMUL;
  1667.     }
  1668. #endif
  1669.     InitColorsX();
  1670.   }
  1671. #ifdef ISG
  1672.   else {
  1673. #ifdef PCG
  1674.     BeginX();
  1675.     if (gs.xWin == 0 || gs.yWin == 0) {
  1676.       if (gs.xWin == 0)
  1677.         gs.xWin = xPcScreen;
  1678.       if (gs.yWin == 0)
  1679.         gs.yWin = yPcScreen;
  1680.       SquareX(&gs.xWin, &gs.yWin, fFalse);
  1681.     } else if (fSidebar)
  1682.       gs.xWin += SIDESIZE;
  1683. #else
  1684.     if (gs.xWin == 0 || gs.yWin == 0) {
  1685.       if (gs.xWin == 0)
  1686.         gs.xWin = DEFAULTX;
  1687.       if (gs.yWin == 0)
  1688.         gs.yWin = DEFAULTY;
  1689.       SquareX(&gs.xWin, &gs.yWin, fFalse);
  1690.     } else if (fSidebar)
  1691.       gs.xWin += SIDESIZE;
  1692.     BeginX();
  1693. #endif
  1694.   }
  1695. #endif /* ISG */
  1696.  
  1697.   if (gi.fFile || gs.fRoot)    /* Go draw the graphic chart. */
  1698.     DrawChartX();
  1699.   if (gi.fFile) {    /* Write bitmap to file if in that mode. */
  1700.     EndFileX();
  1701.     while (gi.yBand) {
  1702.       gi.yOffset -= gi.yBand;
  1703.       DrawChartX();
  1704.       EndFileX();
  1705.     }
  1706.     if (!gs.fPS)
  1707.       DeallocateHuge(gi.bm);
  1708.   }
  1709. #ifdef ISG
  1710.   else {
  1711. #ifdef X11
  1712.     if (gs.fRoot) {                                         /* Process -XB. */
  1713.       XSetWindowBackgroundPixmap(gi.disp, gi.root, gi.pmap);
  1714.       XClearWindow(gi.disp, gi.root);
  1715.  
  1716.       /* If -Xn in effect with -XB, then enter infinite loop where we */
  1717.       /* calculate and animate chart, displaying on the root window.  */
  1718.       while (gs.nAnim) {
  1719.         Animate(gs.nAnim, 1);
  1720.         if (!gs.fJetTrail)
  1721.           XFillRectangle(gi.disp, gi.pmap, gi.pmgc, 0, 0, gs.xWin, gs.yWin);
  1722.         DrawChartX();
  1723.         XSetWindowBackgroundPixmap(gi.disp, gi.root, gi.pmap);
  1724.         XClearWindow(gi.disp, gi.root);
  1725.       }
  1726.     } else
  1727. #endif
  1728.       InteractX();    /* Window's up; process commands given to window now. */
  1729.     EndX();
  1730.   }
  1731. #endif /* ISG */
  1732.   return fTrue;
  1733. }
  1734. #endif /* GRAPH */
  1735.  
  1736. /* xscreen.c */
  1737.